package org.dfl.plugin.editor.commands;

import java.util.ArrayList;
import java.util.List;

import org.dfl.core.data.types.Type;
import org.dfl.core.data.types.TypeManager;
import org.dfl.core.model.TInputEdge;
import org.dfl.plugin.dialogs.EdgePropertiesDialog;
import org.dfl.plugin.dialogs.InputEdgePropertiesDialog;
import org.dfl.plugin.editor.model.ConnectionModelElement;
import org.dfl.plugin.editor.model.NestedConnectionModelElement;
import org.dfl.plugin.editor.model.TransitionModelElement;
import org.eclipse.gef.commands.Command;

/**
 * command that edit connection properties
 * @author Piotr Wlodarczyk
 *
 */
public class ConnectionEditPropertiesCommand extends Command {
	private String newLabel;
	private String oldLabel;

	private ConnectionModelElement conn;
	private boolean isTrueOld;
	private boolean isFalseOld;
	private boolean isEmptyOld;
	private boolean isNotEmptyOld;
	private boolean isTrueNew;
	private boolean isFalseNew;
	private boolean isEmptyNew;
	private boolean isNotEmptyNew;

	public ConnectionEditPropertiesCommand(ConnectionModelElement conn) {
		super();
		this.conn = conn;
	}

	@Override
	public boolean canExecute() {
		if (conn.getSource().getDiagram() == null
				|| !conn.getSource().getDiagram().isEditable())
			return false;
		if(conn.getSource() instanceof TransitionModelElement){
			return false;
		}
		return !(conn instanceof NestedConnectionModelElement);
	}

	@Override
	public void execute() {
		conn.setRefreshDiagramEnabled(false);
		isTrueOld = conn.getEdge().isNeededTrue();
		isFalseOld = conn.getEdge().isNeededFalse();
		isEmptyOld = conn.getEdge().isNeededEmpty();
		isNotEmptyOld = conn.getEdge().isNeededNotempty();
		
		
		EdgePropertiesDialog dialog = null;
		if (isTInputEdge()) {
			TransitionModelElement tme = (TransitionModelElement) conn.getTarget();
			conn.disconnect(); 
			Type type = conn.getEdge().getPlace().getTypeContainer().getType().getCopy();
			if(conn.getEdge().isNested()){
				type = TypeManager.getCollectionType(type);
			}
			List<String> freeInputs = tme.getTransition().getFreeInputs(type);
			boolean fixedLabels = (freeInputs!=null && tme.getTransition().isInputNameNeeded());
			if (freeInputs == null)
				freeInputs = new ArrayList<String>();

			newLabel = ""; //$NON-NLS-1$
			oldLabel = conn.getLabel();

			List<String> freeInputsOK = new ArrayList<String>();
			conn.setNoneProperty();
			for (String in : freeInputs) {
				conn.setLabel(in);
				if (conn.reconnect(true)) {
					freeInputsOK.add(in);
				}
				conn.disconnect();
			}
			pureUndo();
			dialog = new InputEdgePropertiesDialog(conn, freeInputsOK, conn.getLabel(), fixedLabels);
		} else {
			dialog = new EdgePropertiesDialog(conn);
		}

		dialog.open();
		if (dialog.isOkButtonClicked()) {
			if(isTInputEdge()){
				newLabel = ((TInputEdge)conn.getEdge()).getLabel();
			}
			isTrueNew = conn.getEdge().isNeededTrue();
			isFalseNew = conn.getEdge().isNeededFalse();
			isEmptyNew = conn.getEdge().isNeededEmpty();
			isNotEmptyNew = conn.getEdge().isNeededNotempty();
			conn.setRefreshDiagramEnabled(true);
			conn.fireSelfPropChanged();
		} else {
			undo();
			throw new CancelCommandRuntimeException();
		}
	}

	private boolean isTInputEdge() {
		return (conn.getEdge() instanceof TInputEdge);
	}

	@Override
	public boolean canUndo() {
		if (conn.getSource().getDiagram() == null
				|| !conn.getSource().getDiagram().isEditable())
			return false;
		return super.canUndo();
	}

	@Override
	public void undo() {
		conn.setRefreshDiagramEnabled(false);
		pureUndo();
		conn.setRefreshDiagramEnabled(true);
		conn.fireSelfPropChanged();
	}
	
	private void pureUndo(){
		conn.disconnect();
		conn.setNoneProperty();
		if(isTInputEdge())
			conn.setLabel(oldLabel);
		if (isEmptyOld)
			conn.setEmptyProperty();
		if (isNotEmptyOld)
			conn.setNotemptyProperty();
		if (isTrueOld)
			conn.setTrueProperty();
		if (isFalseOld)
			conn.setFalseProperty();
		conn.reconnect(true);
	}

	@Override
	public void redo() {
		conn.setRefreshDiagramEnabled(false);
		conn.disconnect();
		conn.setNoneProperty();
		if(isTInputEdge())
			conn.setLabel(newLabel);
		if (isEmptyNew)
			conn.setEmptyProperty();
		if (isNotEmptyNew)
			conn.setNotemptyProperty();
		if (isTrueNew)
			conn.setTrueProperty();
		if (isFalseNew)
			conn.setFalseProperty();
		conn.reconnect(true);
		conn.setRefreshDiagramEnabled(true);
		conn.fireSelfPropChanged();
	}
}
